﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using gudusoft.gsqlparser;
using generador;
using System.Text.RegularExpressions;
using SQLVis.Entidades;
using System.IO;

namespace parser
{
    public class Program
    {

        private static TGSqlParser sqlparser= new TGSqlParser(TDbVendor.DbVMssql);

        static void Main(string[] args)
        {
            
             //Parse("../../../logslowquerysgenerado.log");
           
            
            //Parse("../../../mysql-slow.1");

//            Parse(@"C:\Users\fpippia\Desktop\HOYTESIS\slowsquerys (FINALES)\modificados\mysql-slow.log");
            Parse(@"../../../nuevolog/TODOELLOG.log");

           // Parse(@"C:\Users\Shulian\Desktop\Tesis\Prototypes\clcv-blog-5\logslowquerysgenerado.log");
        }

        public static IList<SQLPattern> Parse(string strLogPath)
        {
            ArrayList infos_parseadas_del_log = new ArrayList();

            System.IO.StreamReader myFile =  new System.IO.StreamReader( strLogPath );
            // new System.IO.StreamReader("c:\\logslowquerysgenerado.log");

IgnorarPrimeras3Lineas(myFile);

            while (!myFile.EndOfStream)
            {

                InfoDeLaQuery info = ParsearInfoQuery(myFile);
                if (info != null)
                    infos_parseadas_del_log.Add(info);

            }


//Para ariel quitar luego!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!            
           // CrearCSV(infos_parseadas_del_log);
//Para ariel quitar luego FIN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

            AgrupadorDeQuerysPorPatron agrupador = new AgrupadorDeQuerysPorPatron(infos_parseadas_del_log);
            IList<SQLPattern> lista = agrupador.Agrupar();

            myFile.Close();

            //ImpresorDeQuerysPorPatron impresor = new ImpresorDeQuerysPorPatron(lista);
            //impresor.Imprimir();

            return lista;
        }

        private static void CrearCSV(ArrayList infos_parseadas_del_log)
        {
             /// <summary>
            /// These are special characters in CSV files. If a column contains any
            /// of these characters, the entire column is wrapped in double quotes.
            /// </summary>
            char[] specialChars = new char[] { ',', '"', '\r', '\n' };
            char delimiter = ',';
            char quote = '"';

            StreamWriter writer = new StreamWriter(@"../../../nuevolog/TODOELLOG.csv");

            foreach (InfoDeLaQuery info in infos_parseadas_del_log)
            {
                string token = String.Empty;

                WriteCellCsv(specialChars, delimiter, writer, info.Time.ToString());

                WriteCellCsv(specialChars, delimiter, writer, info.UserHost);

                WriteCellCsv(specialChars, delimiter, writer, info.QueryTime.ToString());

                WriteCellCsv(specialChars, delimiter, writer, info.LockTime.ToString());

                WriteCellCsv(specialChars, delimiter, writer, info.RowsSent.ToString());
                
                WriteCellCsv(specialChars, delimiter, writer, info.RowsExamined.ToString());
                 
                WriteCellCsv(specialChars, delimiter, writer, info.QueryAsString);

                writer.WriteLine();
            }
        }

        private static void WriteCellCsv(char[] specialChars, char delimiter, StreamWriter writer,   string token)
        {
            token = QuoteSpecialCharacterColumn(specialChars, token);
            writer.Write(token);

            writer.Write(delimiter);
             
        }

        private static string QuoteSpecialCharacterColumn(char[] specialChars,  string token)
        {
            if (token.IndexOfAny(specialChars) == -1)
                return (token);
            else
            {
                StringBuilder builder= new StringBuilder();
                builder.AppendFormat("\"{0}\"", token.Replace("\"", "\"\""));
                return builder.ToString();

            }
        }

        private static void IgnorarPrimeras3Lineas(System.IO.StreamReader myFile)
        {
            int i = 0;
            while (i<3)
            {
                //primera linea
                string linea = LeerSalteandoLineasEnBlanco(myFile);
                i++;
            }
        }

        

        public static InfoDeLaQuery ParsearInfoQuery(System.IO.StreamReader myFile)
        {
            InfoDeLaQuery info1 = new InfoDeLaQuery();
            string[] temp;

            //primera linea
            string linea = LeerSalteandoLineasEnBlanco(myFile);
           
            if (linea == string.Empty)//LLEGUE AL FINAL DEL ARCHIVO NO TIENE SENTIDO SEGUIR
                return null;

            //PUEDE QUE NO SEA TIME PORQUE ALGUNOS NO TIENEN TIME
            // # Time: 050718 19:45:58 
            temp = linea.Split(' ');

            //PUEDE QUE HAYA UN # administrator command: ADELANTE ENTONCES LO IGNORO
            if (temp[1].Equals("administrator"))
            {
                linea = LeerSalteandoLineasEnBlanco(myFile);
                temp = linea.Split(' ');
            }

            if (temp[1].Equals("Time:"))
            {
                string time = temp[temp.Length - 2] + " " + temp[temp.Length - 1];

                DateTime time_as_date;
                try
                {
                    time_as_date = DateTime.Parse(time);
                }
                catch (Exception)
                {
                    time_as_date = DateTime.ParseExact(time, "yyMMdd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
                }
                info1.Time = time_as_date;

                //segunda linea
                linea = LeerSalteandoLineasEnBlanco(myFile);
                // # User@Host: db[db] @ localhost [127.0.0.1] 
                temp = linea.Split(' ');

            }
            else
            {
                info1.Time = DateTime.MinValue;
            }
            
            
            string userhost = "";
            for (int i = 2; i < temp.Length; i++)
            {
                userhost += temp[i];
            }
            info1.UserHost = userhost;


            //tercera linea
            linea = LeerSalteandoLineasEnBlanco(myFile);
            // # Query_time: 3 Lock_time: 0 Rows_sent: 43 Rows_examined: 10310 

            linea = Regex.Replace(linea, @"\s+", " ");  //me aseguro que solo los separe 1 espacio en blanco y no mas
            temp = linea.Split(' ');
            info1.QueryTime = int.Parse(temp[2]);
            info1.LockTime = int.Parse(temp[4]);
            info1.RowsSent = int.Parse(temp[6]);
            info1.RowsExamined = int.Parse(temp[8]);


            //la query
            linea = //LeerHastaLaProximaLineaEnBlancoConcatenando(myFile); 
            LeerSQLConcatenandoHastaLaProximaInfoquery(myFile);
            
            sqlparser.SqlText.Text =  linea;
            int iRet = sqlparser.Parse();

            if (iRet == 0)//todo ok
            {

                 var first= sqlparser.SqlStatements.ExtractFirst(); //solo asigne un statement en el generador!
                 if (first is TMssqlUse)
                     info1.Query = sqlparser.SqlStatements.ExtractFirst();
                 else
                     info1.Query = first;
            }
            else
            {
                throw new Exception("HUBO ERROR EN EL PARSEO DE LA QUERY");
            }

            return info1;
        }

        private static string LeerSQLConcatenandoHastaLaProximaInfoquery(System.IO.StreamReader myFile)
        {
            string result = LeerSalteandoLineasEnBlanco(myFile); //primer linea del sql
            char comienzoInfoQuery='#';

            string temp="comenzar";
            while (!myFile.EndOfStream && Convert.ToChar(myFile.Peek()) != comienzoInfoQuery && temp != String.Empty) //
            { 
                if (!myFile.EndOfStream)
                {
                    temp = myFile.ReadLine();
                    result += "  " + temp; //dejo espacio para no pegar palabras del statement que originalmente estan en 2 renglones distintos 
                }
                else
                {
                    temp = string.Empty; //esto es porque no deje un espacio blanco al final del archivo!!
                }
            
            }

            return result;
        }



        //private static string LeerHastaLaProximaLineaEnBlancoConcatenando(System.IO.StreamReader myFile)
        //{
        //    string result = LeerSalteandoLineasEnBlanco(myFile);
        //    if (result != string.Empty)
        //    {
        //        string temp;
        //        do
        //        {
        //            if (!myFile.EndOfStream)
        //            {
        //                temp = myFile.ReadLine();
        //                result += "  " + temp; //dejo espacio para no pegar palabras del statement que originalmente estan en 2 renglones distintos 
        //            }
        //            else 
        //            {
        //                temp = string.Empty; //esto es porque no deje un espacio blanco al final del archivo!!
        //            }
        //        } while (temp != String.Empty );
            
        //    }
           
        //    return result;
        //}

        //si retorna string en blanco es que llegue al final!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        private static string LeerSalteandoLineasEnBlanco(System.IO.StreamReader myFile)
        {
            string result = String.Empty; 

            while(result==String.Empty && !myFile.EndOfStream)
            {
                result = myFile.ReadLine();
            }

            return result;
        }

        //private static void ChequearElTipoDeStatementParaAgruparlos(TCustomSqlStatement statement, InfoDeLaQuery info1)
        //{
        //     switch (statement.SqlStatementType)
        //    {
        //        case TSqlStatementType.sstSelect:
        //            break;
        //        case TSqlStatementType.sstDelete:
        //            break;
        //        case TSqlStatementType.sstInsert:
        //            //algo
        //            break;
        //        case TSqlStatementType.sstUpdate:
        //            //otro algo
        //            break;

        //        default:
        //            throw new Exception("no es de los tipos de statement que genere el statement parseado!!")
        //            break;
        //}

    }
}
